using Microsoft.EntityFrameworkCore;
using ZeroSum.Application.Datas;
using ZeroSum.Application.Extensions;
using ZeroSum.Domain.Datas;
using ZeroSum.Domain.Repositories;
using ZeroSum.Exceptions;
using ZeroSum.Infrastructure.Extensions;
using ZeroSum.Mapper.Mappers;
using ZeroSumDBM.Application.Services.DataServers.Dto.In;
using ZeroSumDBM.Application.Services.DataServers.Dto.Out;
using ZeroSumDBM.Application.Services.DataServers.Dto.Query;
using ZeroSumDBM.Core.Aggregates.DB;
using ZeroSumDBM.Core.MySql;

namespace ZeroSumDBM.Application.Services.DataServers;

public class DataServerService : IDataServerService
{
    private readonly IRepository<DataServer> _repository;

    public DataServerService(IRepository<DataServer> repository)
    {
        _repository = repository;
    }

    public async Task Add(AddDataServerDto dto)
    {
        var entity = dto.MapTo<DataServer>();
        await _repository.InsertAsync(entity, true);
    }

    public async Task Delete(DeleteDataServerDto dto)
    {
        await CheckExist(dto.Id);
        var entity = await _repository.SingleOrDefaultAsync(x => x.Id == dto.Id);
        await _repository.DeleteAsync(entity);
    }

    public async Task<PagedList<PageDataServerDto>> Page(PageDataServerQuery query)
    {
        var keyword = !string.IsNullOrEmpty(query.Keyword?.Trim());
        var entities = await _repository.Query
#pragma warning disable CS8602 // 解引用可能出现空引用。
            .WhereIf(keyword, u => EF.Functions.Like(u.Account, $"%{query.Keyword.Trim()}%"))
#pragma warning restore CS8602 // 解引用可能出现空引用。
            .Select(x => x.MapTo<PageDataServerDto>())
            .ToPagedListAsync(query.PageIndex, query.PageSize);
        return entities;
    }

    public async Task<List<ListDataServerDto>> List(ListDataServerQuery query)
    {
        var keyword = !string.IsNullOrEmpty(query.Keyword?.Trim());
        var entities = await _repository.Query
#pragma warning disable CS8602 // 解引用可能出现空引用。
            .WhereIf(keyword, u => EF.Functions.Like(u.Account, $"%{query.Keyword.Trim()}%"))
#pragma warning restore CS8602 // 解引用可能出现空引用。
            .Where(u => u.Status == CommonStatus.Enable)
            .Select(u => u.MapTo<ListDataServerDto>())
            .ToListAsync();
        return entities;
    }

    public async Task Edit(EditDataServerDto dto)
    {
        await CheckExist(dto.Id);

        var entity = await _repository.SingleOrDefaultAsync(x => x.Id == dto.Id);

        var editEntity = dto.MapTo(entity);
        await _repository.UpdateAsync(editEntity);
    }

    public async Task<DetailDataServerDto> Detail(DetailDataServerQuery query)
    {
        await CheckExist(query.Id);
        var entity = await _repository.SingleOrDefaultAsync(x => x.Id == query.Id);
        return entity.MapTo<DetailDataServerDto>();
    }

    public async Task<List<string>> GetDatabases(long id)
    {
        await CheckExist(id);
        var entity =
            await _repository.SingleOrDefaultAsync(x =>
                x.Id == id && x.Status != CommonStatus.Deleted);
        var list = MysqlHelper.ShowDataBase(entity.Host, entity.Account, entity.Password, entity.Port);
        return list.ToList();
    }

    public async Task<List<string>> GetTables(long id, string database)
    {
        await CheckExist(id);
        var entity =
            await _repository.SingleOrDefaultAsync(x =>
                x.Id == id && x.Status != CommonStatus.Deleted);
        var list = MysqlHelper.ShowTables(entity.Host, entity.Account, entity.Password, entity.Port, database);
        return list;
    }

    public async Task<SearchResult> GetTableData(TableDataQuery query)
    {
        await CheckExist(query.Id);
        var entity =
            await _repository.SingleOrDefaultAsync(x =>
                x.Id == query.Id && x.Status != CommonStatus.Deleted);
        return MysqlHelper.GetTableData(entity.Host, entity.Account, entity.Password, entity.Port, query.Database,
            query.Table, query.Page, query.PageSize
        );
    }

    private async Task CheckExist(long id)
    {
        var isExist = await _repository.Query
            .AnyAsync(u => u.Id == id && u.Status != CommonStatus.Deleted);
        if (!isExist)
#pragma warning disable CS8597 // 抛出的值可能为 null。
            throw AlreadyExistedException.Of($"编号为“{id}”的已存在！");
#pragma warning restore CS8597 // 抛出的值可能为 null。
    }
}